#pragma once
#include "LevelElement.h"
#include "InputState.h"
#include "d3dUtil.h"
#include <vector>
using namespace std;

class DX10MaterialIndexBuffer;
struct SpotLight;
class Skeleton;
#include "Animation.h"
class PhysicsMesh;


/**
* Contains the same information as the ObjMesh object but with
* all the internal data as DirectX10 buffers and implements the GraphBase
* interface.
*/
class DX10ObjMesh:public LevelElement
{
public:
        /**
        * Creates a new DirectX10 ObjMesh object
        * @param effect the location of the effect file.
        * @param technique the name of the technique to use.
        */
        DX10ObjMesh(tstring effect,tstring technique);
        /**
        * Delets the DirectX10 ObjMesh object
        */
        virtual ~DX10ObjMesh(void);

        /**
        * Returns the default technique for this object.
        */
        ID3D10EffectTechnique* GetDefaultTechnique() const{
                return m_pDefaultTechnique;
        }

        void CreateEffect(ContentManager *pContentManager);

        /**
        * Init
        * Load obj and physics mesh.
        */
        void Initialize(ContentManager* contentManager, ID3D10Device* pDevice);

        void CreateEffect(ContentManager* contentManager, ID3D10Device *pDevice);

        /**
        * Returns the effect that is used by this object.
        */
        ID3D10Effect* GetEffect() const{
                return m_pDefaultEffect;
        }

        /**
        * Commits the effect parameters to the effect.
        */
        void GetEffectVariables(ID3D10Effect* effect);
        /**
        * Updates the common effect parameters.
        */
        void UpdateEffectVariables(const RenderContext* renderContext) const;

        /**
        * Sets the vertexbuffer to use with this DX10ObjMesh object.
        * @param buffer the buffer to set.
        */
        void SetVertexBuffer(ID3D10Buffer* buffer, int stride){
                m_pVertexBuffer = buffer;
                m_VertexBufferStride = stride;
        }

        /**
        * Sets the input layout to use for this DX10ObjMesh object.
        * @param layout the layout to set.
        */
        void SetInputLayout(ID3D10InputLayout* layout){
                m_pInputLayout = layout;
        }

        /**
        * Adds a DX10MaterialIndexBuffer object to the list of indexbuffers
        * with materials to draw.
        * @param buffer the buffer to add.
        */
        void AddIndexBuffer(DX10MaterialIndexBuffer* buffer){
                m_IndexBuffers.push_back(buffer);
        }

        /**
        * Adds the spotlights to the vector of spotlights.
        */
        void AddSpotLights(vector<SpotLight*>& lights){
                m_SpotLights.assign(lights.begin(),lights.end());
        }

        /**
        * Sets the skeleton to use for this mesh.
        * @param skeleton the skeleton for this mesh.
        */ 
        void SetSkeleton(Skeleton* skeleton);

        /**
        * Returns the skeleton to use for this mesh.
        * @return the skeleton that is used by this mesh.
        */
        Skeleton* GetSkeleton(){
                return m_pSkeleton;
        }

        /**
        * Checks if the mesh is animated or not.
        * @return true if the mesh is animated false otherwise.
        */
        bool IsAnimated()const{
                return m_pSkeleton != NULL;
        }

        /**
        * Adds an animation to the map of animations.
        * @param animation the animation to add.
        */
        void AddAnimation( Animation* pAnimation);
        /**
        * Adds an animation to the map of animations.
        * @param animation the animation to add.
        */
        void AddAnimation( AnimationPtr pAnimation);

        /**
        * Activates the animation for the skeleton.
        * @param key the name of the animation to activate.
        */
        void ActivateAnimation(tstring key,bool looping=true)const;

        /**
        * Tick
        * @param dTime the time passed since the last Tick.
        */
        virtual void Tick(const InputState &);

        /**
        * Init
        * Load obj and physics mesh.
        */
        virtual void Initialize(ContentManager* contentManager);

        /**
        * Draw using the default technique.
        */
        virtual void Draw(const RenderContext* renderContext, ID3D10ShaderResourceView* shadowdepthmap = 0);

        /**
        * Draw using a custom technique.
        * @param pTechnique the technique to use.
        */
        virtual void Draw(const RenderContext* renderContext, const ID3D10EffectTechnique* pTechnique);

        /**
        * On Resize
        */
        virtual void OnResize();
        /**
        * Sets the current diffuse texture for the rendering.
        * @param texture the texture to use.
        */
        void SetDiffuseTexture(ID3D10ShaderResourceView * texture) const;
        /**
        * Sets the current normal map texture for the rendering.
        * @param normalMapTexture the normal map texture to use.
        */ 
        void SetNormalMapTexture(ID3D10ShaderResourceView * texture) const;

        void SetSynchronizeWithPhyiscs(bool sync){m_SynchronizeWithPhysics = sync;}
        void SetActor(PhysicsMesh* pActor){m_pActor = pActor;}
        virtual void DrawToShadowmap(GraphCamera* pOrtohCam, D3DXMATRIX &mLightVolume
        ,ID3D10Effect* BuildShadowMapFX);
protected:
		wstring													m_TechiqueName;
        /**
        * The effect file name
        */
        wstring                                                         m_EffectFileName;
        /**
        * The vertex buffer for this mesh object
        */
        ID3D10Buffer*                                           m_pVertexBuffer;
        /**
        * The stride of the vertexbuffer.
        */
        UINT                                                            m_VertexBufferStride;
        /**
        * The input layout for the vertex buffer.
        */
        ID3D10InputLayout*                                      m_pInputLayout;
        /**
        * The D3DX10MaterialIndexBuffer objects.
        */
        vector<DX10MaterialIndexBuffer*>        m_IndexBuffers;
        /**
        * The spotlights to use for this object.
        */
        vector<SpotLight*> m_SpotLights;

        /**
        * The rig or skeleton for this mesh.
        */
        Skeleton* m_pSkeleton;

        // the common effect parameters
        ID3D10EffectMatrixVariable* m_pWorldViewProjectionVariable;
        ID3D10EffectMatrixVariable* m_pWorldVariable;
        ID3D10EffectVariable* m_pSpotLight1Variable;
        ID3D10EffectVariable* m_pSpotLight2Variable;
        ID3D10EffectVariable* m_pBoneMatrices;

        ID3D10Effect*                           m_pDefaultEffect;
        ID3D10EffectTechnique*          m_pDefaultTechnique;

        ID3D10EffectVectorVariable* m_pEyePosVariable;
        mutable ID3D10EffectShaderResourceVariable* m_pDiffuseMapVariable;
        mutable ID3D10EffectShaderResourceVariable* m_pNormalMapVariable;

        // physics
        bool m_SynchronizeWithPhysics;
        PhysicsMesh* m_pActor;

        GraphCamera* m_OrthoCam;
        ID3D10ShaderResourceView *m_Texture;
private:
        // -------------------------
        // Disabling default copy constructor and default assignment operator.
        // If you get a linker error from one of these functions, your class is internally trying to use them. This is
        // an error in your class, these declarations are deliberately made without implementation because they should never be used.
        // -------------------------
        DX10ObjMesh(const DX10ObjMesh& t);
        DX10ObjMesh& operator=(const DX10ObjMesh& t);
};
